package cn.example.web.config;

import com.jfinal.core.Controller;
import org.artifact.core.lang.IServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * ControllerFactory
 */
public class ControllerFactory extends com.jfinal.core.ControllerFactory {
 
    private ThreadLocal<Map<Class<? extends Controller>, Controller>> buffers = new ThreadLocal<Map<Class<? extends Controller>, Controller>>() {
        protected Map<Class<? extends Controller>, Controller> initialValue() {
            return new HashMap<Class<? extends Controller>, Controller>();
        }
    };
 
    public Controller getController(Class<? extends Controller> controllerClass) throws InstantiationException, IllegalAccessException {
        Controller ret = buffers.get().get(controllerClass);
        if (ret == null) {
            ret = controllerClass.newInstance();
            autoInject(ret);
            buffers.get().put(controllerClass, ret);
        }
        return ret;
    }
 
    /**
     * 自动注入
     * @param ret controller
     */
    public void autoInject(Controller ret) {
    	ApplicationContext springContext = IServer.me().getContext().getSpringContext();
        Field[] fields = ret.getClass().getDeclaredFields();
        for (Field field : fields) {
            Object bean = null;
            if (field.isAnnotationPresent(Autowired.class)) {
                try {
                    bean = springContext.getBean(field.getName());
                } catch (Exception e) {
                }
                if (null == bean) {
                    try {
                        bean = springContext.getBean(field.getType());
                    } catch (Exception e) {
                    }
                }
                if (null == bean) {
                    Autowired annotation = field.getAnnotation(Autowired.class);
                    if (annotation.required()) {
                        throw new RuntimeException(String.format("Error creating bean with name '%s': Injection of autowired dependencies failed.",field.getName()));
                    }
                }
            } else if (field.isAnnotationPresent(Resource.class)) {
                Resource annotation = field.getAnnotation(Resource.class);
                bean = springContext.getBean(annotation.name().trim().length() == 0 ? field.getName() : annotation.name());
            } else
                continue;
            try {
                if (bean != null) {
                    field.setAccessible(true);
                    field.set(ret, bean);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}